#include "bakalarka.h"

windowHistory::windowHistory(){}

void windowHistory::setHistory(mdiWindow &window){

	if(path.isEmpty() || path != window.currentFile())
		return;
	
	drawArea *area = window.getDrawArea();
	QMdiSubWindow *subWindow = qobject_cast<QMdiSubWindow *>(window.parent());

	area->setMatrix(matrix);
	subWindow->setWindowState(state);
	subWindow->move(point);
	if(state != Qt::WindowMaximized || state != Qt::WindowFullScreen)
		subWindow->setGeometry(rect);
	area->update();


}

void windowHistory::memberWindow(mdiWindow &window){

	drawArea *area = window.getDrawArea();
	QMdiSubWindow *subWindow = qobject_cast<QMdiSubWindow *>(window.parent());
	
	matrix = area->getMatrix();
	path = window.currentFile();
	point = subWindow->pos();
	rect = subWindow->geometry();
	state = subWindow->windowState();

}

void windowHistory::writeSettings(QSettings &settings){

	if(path.isEmpty())
		return;

	settings.setValue(SETTINGS_HISTORY "_matrix", matrix);
	settings.setValue(SETTINGS_HISTORY "_path", path);
	settings.setValue(SETTINGS_HISTORY "_point", point);
	settings.setValue(SETTINGS_HISTORY "_rect", rect);
	settings.setValue(SETTINGS_HISTORY "_state", (int)state);

}

void windowHistory::readSettings(QSettings &settings){

	if(qvariant_cast<QString>(settings.value(SETTINGS_HISTORY "_path")).isEmpty())
		return;
	
	path = qvariant_cast<QString>(settings.value(SETTINGS_HISTORY "_path"));
	matrix = qvariant_cast<QMatrix>(settings.value(SETTINGS_HISTORY "_matrix"));
	point = qvariant_cast<QPoint>(settings.value(SETTINGS_HISTORY "_point"));
	rect = qvariant_cast<QRect>(settings.value(SETTINGS_HISTORY "_rect"));
	state = (Qt::WindowStates)qvariant_cast<int>(settings.value(SETTINGS_HISTORY "_state"));
	
}

bakalarka::bakalarka(): once(true){
	
	mdiArea = new QMdiArea;
	mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
	mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
	setCentralWidget(mdiArea);
	windowMapper = new QSignalMapper(this);
	connect(windowMapper, SIGNAL(mapped(QWidget *)), this, SLOT(setActiveSubWindow(QWidget *)));
	connect(mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow *)), this, SLOT(activateWindow(QMdiSubWindow *)));

	fileProcess = false;
	lastActivateWindow = 0;
	createStatusBar();
	createObjects();
	createTranslate();
	createRotate();
	createTool();
	createMorph();
	createActions();
	createMenus();
	createToolBar();
	readSettings();
	setWindowTitle(tr(SETTINGS_PRODUCT));
	setUnifiedTitleAndToolBarOnMac(true);
	setWindowIcon(QIcon(":img/lego.png"));
    connect(this, SIGNAL(openFileByArg(QString)), this, SLOT(newMdiWindow(QString)));

}

void bakalarka::paintEvent(QPaintEvent *event){

    if(once){
        QStringList argv(QCoreApplication::arguments());

        if(argv.size() > 1){
            QDir path(argv.at(1));
            QString absolute(path.absolutePath());

            emit openFileByArg(absolute);
        }
        once = false;
    }

}

void bakalarka::openEdit(){
	
	textEditDialog dialog(this);
	mdiWindow *mdi = activeMdiWindow();
	
	if(mdi){
		if(mdi->isWindowModified())
			QMessageBox::information(this, tr("Editace"), tr("Před spuštěním editace musí být soubor uložen."));
		else{
			mdi->turnOffWatcher();
			dialog.setFile(mdi->currentFile());
			dialog.resize(640, 480);
			dialog.exec();
		
			if(dialog.isModified()){
				QMdiSubWindow *subWindow = findMdiWindow(dialog.getFile());
				
				if(subWindow)	
					reloadSubWindow(subWindow);
			}
		}
	}

}

void bakalarka::openPreview3d(){

	mdiWindow *mdi = activeMdiWindow();
	
	if(mdi){
		drawArea *area = mdi->getDrawArea();
		glDialog dialog(this, mdi->currentFile(), mdi->getContainer(), area->getBuffContainer());
		
		dialog.resize(480, 480);
		dialog.exec();
	}

}

void bakalarka::openAbout(){

	aboutDialog aboutD(this);
	
	aboutD.exec();

}

assistant *bakalarka::getAssistant(){

	return &helpAssistant;

}

void bakalarka::saveWindowHistory(mdiWindow &window){

	history.memberWindow(window);

}

void bakalarka::createActions(){

	open  = new QAction(tr("Otevrit"), this);
	open->setIcon(QIcon(":img/document-open.png"));
	open->setShortcut(tr("Ctrl+O"));
	open->setStatusTip(tr("Otevre existujici soubor."));
	connect(open, SIGNAL(triggered()), this, SLOT(openSlot()));
	
	save = new QAction(tr("Ulozit"), this);
	save->setIcon(QIcon(":img/document-save.png"));
	save->setShortcut(tr("Ctrl+S"));
	save->setStatusTip(tr("Ulozi dokument na disk."));
	connect(save, SIGNAL(triggered()), this, SLOT(saveSlot()));
	
	saveAs = new QAction(tr("Ulozit jako"), this);
	saveAs->setIcon(QIcon(":img/document-save-as.png"));
	saveAs->setStatusTip(tr("Ulozi dokument na disk pod novym jmenem."));
	connect(saveAs, SIGNAL(triggered()), this, SLOT(saveAsSlot()));
	
	quit = new QAction(tr("Ukoncit"), this);
	quit->setShortcut(tr("Ctrl+Q"));
	quit->setStatusTip(tr("Ukonci program se vsemi jeho okny."));
	connect(quit, SIGNAL(triggered()), this, SLOT(close()));
	
	showObjects = dynamic_cast<QDockWidget *>(view->parent())->toggleViewAction();
	showObjects->setShortcut(tr("Ctrl+B"));
	
	showTranslate = dynamic_cast<QDockWidget *>(translate->parent())->toggleViewAction();
	showTranslate->setShortcut(tr("Ctrl+T"));
	
	showRotate = dynamic_cast<QDockWidget *>(rotate->parent())->toggleViewAction();
	showRotate->setShortcut(tr("Ctrl+R"));
	
	showTool = dynamic_cast<QDockWidget *>(tool->parent())->toggleViewAction();
	
	showMorph =  dynamic_cast<QDockWidget *>(morph->parent())->toggleViewAction();
	
	toolOpen = new QAction(tr("Otevře existující soubor."), this);
	toolOpen->setIcon(QIcon(":img/tool-open.png"));
	connect(toolOpen, SIGNAL(triggered()), this, SLOT(openSlot()));
	
	toolSave = new QAction(tr("Uloží dokument na disk."), this);
	toolSave->setIcon(QIcon(":img/tool-save.png"));
	connect(toolSave, SIGNAL(triggered()), this, SLOT(saveSlot()));

	toolSaveAs = new QAction(tr("Uloží dokument na disk pod novým jménem."), this);
	toolSaveAs->setIcon(QIcon(":img/tool-save-as.png"));
	connect(toolSaveAs, SIGNAL(triggered()), this, SLOT(saveAsSlot()));
	
	toolZoomIn = new QAction(tr("Přiblížit"), this);
	toolZoomIn->setShortcut(QKeySequence::ZoomIn);
	toolZoomIn->setIcon(QIcon(":img/zoom-in.png"));
	connect(toolZoomIn, SIGNAL(triggered()), this, SLOT(zoomIn()));
	
	toolZoomOut = new QAction(tr("Oddálit"), this);
	toolZoomOut->setShortcut(QKeySequence::ZoomOut);
	toolZoomOut->setIcon(QIcon(":img/zoom-out.png"));
	connect(toolZoomOut, SIGNAL(triggered()), this, SLOT(zoomOut()));
	
	toolZoomFit = new QAction(tr("Přizpůsobit"), this);
	toolZoomFit->setIcon(QIcon(":img/zoom-fit-best.png"));
	connect(toolZoomFit, SIGNAL(triggered()), this, SLOT(zoomFit()));
	
	toolZoomOriginal = new QAction(tr("Originalní velikost"), this);
	toolZoomOriginal->setIcon(QIcon(":img/zoom-original.png"));
	connect(toolZoomOriginal, SIGNAL(triggered()), this, SLOT(zoomOriginal()));
	
	preview3d = new QAction(tr("Náhled"), this);
	preview3d->setShortcut(tr("Ctrl+n"));
	connect(preview3d, SIGNAL(triggered()), this, SLOT(openPreview3d()));
	
	edit = new QAction(tr("Editace"), this);
	edit->setShortcut(tr("Ctrl+e"));
	connect(edit, SIGNAL(triggered()), this, SLOT(openEdit()));
	
	help = new QAction(tr("Nápověda"), this);
	help->setShortcut(tr("F1"));
	help->setIcon(QIcon(":img/help.png"));
	help->setStatusTip(tr("Zobrazí stránky s manuálem"));
	connect(help, SIGNAL(triggered()), this, SLOT(openManual()));
	
	home = new QAction(tr("O programu"), this);
	home->setStatusTip("Základní informace o LegoPlot.");
	connect(home, SIGNAL(triggered()), this, SLOT(openAbout()));
	
}

void bakalarka::openManual(){

	helpAssistant.showDocumentation("manual.htm");

}

void bakalarka::createMenus(){

	openedFiles = new recentlyOpened(tr("Naposledy otevřené"));
	connect(openedFiles, SIGNAL(triggered(QAction *)), this, SLOT(quickOpen(QAction *)));

	file = menuBar()->addMenu(tr("Soubor"));
	file->addAction(open);
	file->addAction(save);
	file->addAction(saveAs);
	file->addMenu(openedFiles);
	file->addSeparator();
	file->addAction(quit);	
	
	showMenu = menuBar()->addMenu(tr("Zobrazit"));
	showMenu->addAction(showObjects);
	showMenu->addAction(showTranslate);
	showMenu->addAction(showRotate);
	showMenu->addAction(showTool);
	showMenu->addAction(showMorph);
	
	scale = showMenu->addMenu(tr("Měřítko"));
	scale->addAction(toolZoomIn);
	scale->addAction(toolZoomOut);
	scale->addAction(toolZoomFit);
	
	toolMenu = menuBar()->addMenu(tr("Nástroje"));
	toolMenu->addAction(preview3d);
	toolMenu->addAction(edit);
	
	about = menuBar()->addMenu(tr("Pomoc"));
	about->addAction(help);
	about->addAction(home);

}

void bakalarka::createStatusBar(){

	QStatusBar *statusBar = new QStatusBar;
	
	status = new statusWidget;
	statusBar->addPermanentWidget(status, 1);
	setStatusBar(statusBar);

}

void bakalarka::createToolBar(){

	fileToolBar = addToolBar(tr("Soubor"));
	fileToolBar->setObjectName("fileToolBar");
	fileToolBar->addAction(toolOpen);
	fileToolBar->addAction(toolSave);
	fileToolBar->addAction(toolSaveAs);
	
	scaleToolBar = addToolBar(tr("Měřítko"));
	scaleToolBar->setObjectName("scaleToolBar");
	scaleToolBar->addAction(toolZoomIn);
	scaleToolBar->addAction(toolZoomOut);
	scaleToolBar->addAction(toolZoomFit);
	scaleToolBar->addAction(toolZoomOriginal);

}

void bakalarka::setActiveSubWindow(QWidget *window){

	if(!window)
		view->setModel(0);
	else
		mdiArea->setActiveSubWindow(qobject_cast<QMdiSubWindow *>(window));

}

void bakalarka::activateWindow(QMdiSubWindow *window){

	if(!window){
        //not necessary
        //view->setModel(0);
		return;
	}
	else{
		mdiWindow *mdi = qobject_cast<mdiWindow *>(window->widget());
		view->setModel(mdi->getModel());
		if(mdi->getModel()){
			status->setActiveObject(mdi->getActiveObject());
			setScale();
			if(window != lastActivateWindow){
				translate->cancelClicked();
				rotate->cancelClicked();
				tool->cancelClicked();
			}
			lastActivateWindow = window;
		}
		mdiArea->setActiveSubWindow(qobject_cast<QMdiSubWindow *>(window));
	}

}

void bakalarka::createObjects(){
	
	view = new gObjects(this);
	QDockWidget *dockWidget = new QDockWidget(tr("Objekty"), this);
	dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
	dockWidget->setWidget(view);
	dockWidget->setObjectName("dockObjects");
	addDockWidget(Qt::RightDockWidgetArea, dockWidget);

}

void bakalarka::createTranslate(){

	translate = new translateTool(this);
	
	QDockWidget *dockWidget = new QDockWidget(tr("Posun"), this);
	dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
	dockWidget->setWidget(translate);
	dockWidget->setObjectName("dockTranslate");
	addDockWidget(Qt::RightDockWidgetArea, dockWidget);

}

void bakalarka::createRotate(){

	rotate = new rotateTool(this);
	
	QDockWidget *dockWidget = new QDockWidget(tr("Rotace"), this);
	dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
	dockWidget->setWidget(rotate);
	dockWidget->setObjectName("dockRotate");
	addDockWidget(Qt::RightDockWidgetArea, dockWidget);
	tabifyDockWidget(dynamic_cast<QDockWidget *>(translate->parentWidget()), dockWidget);

}

void bakalarka::createTool(){

	tool = new toolTool(this);
	
	QDockWidget *dockWidget = new QDockWidget(tr("Nástroj"), this);
	dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
	dockWidget->setWidget(tool);
	dockWidget->setObjectName("dockTool");
	addDockWidget(Qt::RightDockWidgetArea, dockWidget);
	tabifyDockWidget(dynamic_cast<QDockWidget *>(rotate->parentWidget()), dockWidget);

}

void bakalarka::createMorph(){

	morph = new morphTool(this);
	
	QDockWidget *dockWidget = new QDockWidget(tr("Morph"), this);
	dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
	dockWidget->setWidget(morph);
	dockWidget->setObjectName("dockMorph");
	addDockWidget(Qt::RightDockWidgetArea, dockWidget);
	tabifyDockWidget(dynamic_cast<QDockWidget *>(rotate->parentWidget()), dockWidget);

}

void bakalarka::openSlot(){

	QString fileName = QFileDialog::getOpenFileName(this);
	if(!fileName.isEmpty()){
		QMdiSubWindow *existing = findMdiWindow(fileName);
		if(existing)
			mdiArea->setActiveSubWindow(existing);
		else
			newMdiWindow(fileName);
	}

}

void bakalarka::showCoordinates(QPointF *point){

	status->setCoords(*point);

}

void bakalarka::showObject(gObject *object){
	
	status->setActiveObject(object);

}

void bakalarka::closeSubWindow(QMdiSubWindow *subWindow){

	mdiArea->removeSubWindow(subWindow);

}

void bakalarka::closeSubWindow(const QString &fileName){

	QMdiSubWindow *existing = findMdiWindow(fileName);
	
	if(existing)
		existing->close();

}

void bakalarka::reloadSubWindow(QMdiSubWindow *subWindow){
	
	QString file(qobject_cast<mdiWindow *>(subWindow->widget())->currentFile());
	
	subWindow->close();
	newMdiWindow(file);
	
}

QMdiSubWindow *bakalarka::findMdiWindow(const QString &fileName){

	QString canonicalFilePath = QFileInfo(fileName).canonicalFilePath();
	QList<QMdiSubWindow *> list(mdiArea->subWindowList());
	QList<QMdiSubWindow *>::iterator iter = list.begin();
	
	for(; iter != list.end(); iter++){
		mdiWindow *mdi = qobject_cast<mdiWindow *>((*iter)->widget());
		if(mdi->currentFile() == canonicalFilePath)
			return *iter;
	}
	return 0;

}

drawArea *bakalarka::getDrawArea() const{

	QMdiSubWindow *subWindow = mdiArea->activeSubWindow();
	
	if(subWindow)
		return qobject_cast<mdiWindow *>(subWindow->widget())->getDrawArea();
	return 0;

}

void bakalarka::zoomIn(){

	drawArea *area = getDrawArea();
	QPointF point;

	if(!area)
		return;
	point.setX(1.1);
	point.setY(1.1);
	area->setScale(point);

}

void bakalarka::zoomOut(){

	drawArea *area = getDrawArea();
	QPointF point;

	if(!area)
		return;
	point.setX(0.9);
	point.setY(0.9);
	area->setScale(point);

}

void bakalarka::zoomFit(){

	drawArea *area = getDrawArea();
	QPointF point;

	if(!area)
		return;
	area->focus(0, false);

}

void bakalarka::zoomOriginal(){

	drawArea *area = getDrawArea();
	QPointF point;

	if(!area)
		return;
	area->getScale(point);
	point.setX(1 / point.x());
	point.setY(1 / point.y());
	area->setScale(point);

}

void bakalarka::setScale(){

	drawArea *area = getDrawArea();
	QPointF point;

	if(!area)
		return;
	area->getScale(point);
	status->setScale(point.x());

}

mdiWindow *bakalarka::activeMdiWindow() const{
	
	QMdiSubWindow *activeSubWindow = mdiArea->activeSubWindow();

	if(activeSubWindow)
		return qobject_cast<mdiWindow *>(activeSubWindow->widget());
	return 0;
	
}

void bakalarka::saveSlot(){
	
	mdiWindow *mdi = activeMdiWindow();
	
	if(mdi && !fileProcess){
		fileProcess = true;
		if(mdi->save(mdi->currentFile()))
			status->showMessage(tr("Soubor '%1' byl uložen.").arg(mdi->currentFile()), 3000);
	}
	fileProcess = false;

}

void bakalarka::saveAsSlot(){
	
	mdiWindow *mdi = activeMdiWindow();
	
	if(mdi && !fileProcess){
		fileProcess = true;
		if(mdi->saveAs())
			status->showMessage(tr("Soubor '%1' byl uložen.").arg(mdi->currentFile()), 3000);
	}
	fileProcess = false;

}

void bakalarka::readSettings(){

	QSettings settings(SETTINGS_COMPANY, SETTINGS_PRODUCT);
	QByteArray array(qvariant_cast<QByteArray>(settings.value(SETTINGS_NAME_AREA)));
	QStringList files(qvariant_cast<QStringList>(settings.value(SETTINGS_NAME_FILE)));
	
	resize(settings.value(SETTINGS_NAME_SIZE, SETTINGS_DEFAULT_SIZE);
    move(settings.value(SETTINGS_NAME_POS, SETTINGS_DEFAULT_POS);
	if(array.size() != 0)
		restoreState(array);
	openedFiles->restore(files);
	history.readSettings(settings);

}

void bakalarka::writeSettings(){

	QSettings settings(SETTINGS_COMPANY, SETTINGS_PRODUCT);
	QStringList files;
	
	openedFiles->serialization(files);
	settings.setValue(SETTINGS_NAME_SIZE, size());
	settings.setValue(SETTINGS_NAME_POS, pos());
	settings.setValue(SETTINGS_NAME_AREA, saveState());
	settings.setValue(SETTINGS_NAME_FILE, files);
	history.writeSettings(settings);

}

void bakalarka::areaClicked(gTypeGo *go, const QPointF &point){

	QPointF buff;

	if(go)
		buff = point;
	translate->cancelClicked();
	rotate->cancelClicked();
	tool->cancelClicked();
	rotate->setMiddle(buff);
	morph->cancelClicked();

}

void bakalarka::closeEvent(QCloseEvent *event){

	mdiArea->closeAllSubWindows();
	if(mdiArea->currentSubWindow())
		event->ignore();
	else
		event->accept();
	writeSettings();

}

void bakalarka::newMdiWindow(QString fileName){

	mdiWindow *child = new mdiWindow(this);
	QMdiSubWindow *subWindow = new QMdiSubWindow;
	
	subWindow->setWidget(child);
	subWindow->setAttribute(Qt::WA_DeleteOnClose);
	subWindow->setGeometry(0, 0, 640, 480);
	mdiArea->addSubWindow(subWindow);
	if(child->loadSourceFile(fileName)){
		status->clearAll();
		status->showMessage(tr("Soubor '%1' uspěšně otevřen.").arg(fileName), 3000);
		subWindow->show();
		openedFiles->addFile(fileName);
		history.setHistory(*child);
		connect(child, SIGNAL(reloadSubWindow(QMdiSubWindow *)), 
			this, SLOT(reloadSubWindow(QMdiSubWindow *)));
		connect(child, SIGNAL(removeSubWindow(QMdiSubWindow *)),
			this, SLOT(closeSubWindow(QMdiSubWindow *)));
		connect(child, SIGNAL(saveWindowHistory(mdiWindow &)),
			this, SLOT(saveWindowHistory(mdiWindow &)));
        connect(child, SIGNAL(closeSignal(containerModel *)),
            this, SLOT(changeModel(containerModel *)));
	}
	else{
		subWindow->close();
		openedFiles->deleteFile(fileName);
	}

}

void bakalarka::changeModel(containerModel *model){

    if(model == view->getModel()){
        QList<QMdiSubWindow *> list(mdiArea->subWindowList(QMdiArea::ActivationHistoryOrder));

        if(list.size() > 2){
            mdiWindow *window = qobject_cast<mdiWindow *>(list.at(list.size() - 1));

            view->setModel(window->getModel());
        }
        else
            view->setModel(0);
    }
    else
        view->setModel(0);

}

void bakalarka::quickOpen(QAction *action){

	QString fileName(action->text());
	QMdiSubWindow *existing = findMdiWindow(fileName);
	
	if(existing)
		mdiArea->setActiveSubWindow(existing);
	else
		newMdiWindow(fileName);

}
